/*
 * Achieve it All! - Android app to motivate achieving your goals
 * Copyright (C) 2014  Xilconic
 * 
 * This file is part of Achieve it All!.
 *
 * Achieve it All! is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Achieve it All! is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Achieve it All!.  If not, see <http://www.gnu.org/licenses/>
 */
package com.xilconic.achieveitall.persist;

import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteException;

import com.xilconic.achieveitall.domain.Target;
import com.xilconic.achieveitall.persist.AchieveItAllDatabaseContract.TargetContract;

/**
 * The data source of all {@link Target} available to the app.
 * @author Xilconic
 *
 */
public class TargetDataSource {
    private DatabaseOpenHelper dbHelper;
    private SQLiteDatabase database;
    private boolean connectionOpen = false;
    
    public TargetDataSource(Context context){
        dbHelper = new DatabaseOpenHelper(context);
    }

    /**
     * Opens a writable database connection.
     * @throws SQLiteException If the database cannot be opened for writing.
     */
    public void open() throws SQLiteException {
        database = dbHelper.getWritableDatabase();
        connectionOpen = true;
    }
    
    /**
     * Closes the database connection.
     */
    public void close() {
        database.close();
        connectionOpen = false;
    }

    /**
     * Checks if there is already an open database connection. 
     * @return True if already connected to the database; False otherwise.
     */
    public boolean isOpen() {
        return connectionOpen;
    }

    /**
     * Inserts a new instance of {@link Target} into the database.
     * @param target The instance to be persisted.
     * @return The persisted instance as stored in the database.
     */
    public Target InsertTarget(Target target) {
        if(target.getId() != -1){
            throw new AssertionError("Expecting ID of -1, indicating Target is not part of Database yet. Fault detected.");
        }
        
        ContentValues values = createContentValues(target);
        long insertId = database.insert(TargetContract.TABLE_NAME, null, values);
        if(insertId == -1){
            // TODO: Handle error!
        }

        Cursor cursor = database.query(
                TargetContract.TABLE_NAME, // table name
                TargetContract.getAllColumns(), // columns
                TargetContract._ID + " = '" + insertId + "'", // selection
                null, // selection args
                null, // group by
                null, // having
                null // order by
                );
        cursor.moveToFirst(); // TODO: Handle returning -1
        Target persistedTarget = getPersistedTarget(cursor); // TODO: Handle exception
        cursor.close();
        
        return persistedTarget;
    }

    private Target getPersistedTarget(Cursor cursor) throws IllegalArgumentException {
        Target target = new Target();
        target.setId(cursor.getLong(cursor.getColumnIndexOrThrow(TargetContract._ID)));
        target.setName(cursor.getString(cursor.getColumnIndexOrThrow(TargetContract.COLUMN_NAME_NAME)));
        target.setDescription(cursor.getString(cursor.getColumnIndexOrThrow(TargetContract.COLUMN_NAME_DESCRIPTION)));
        boolean isFinished = cursor.getInt(cursor.getColumnIndexOrThrow(TargetContract.COLUMN_NAME_IS_FINISHED)) > 0;
        target.setFinished(isFinished);
        target.setPointsReward(cursor.getInt(cursor.getColumnIndexOrThrow(TargetContract.COLUMN_NAME_POINTS_REWARD)));
        
        return target;
    }

    private ContentValues createContentValues(Target target) {
        ContentValues values = new ContentValues();
        values.put(TargetContract.COLUMN_NAME_NAME, target.getName());
        values.put(TargetContract.COLUMN_NAME_DESCRIPTION, target.getDescription());
        values.put(TargetContract.COLUMN_NAME_IS_FINISHED, target.isFinished());
        values.put(TargetContract.COLUMN_NAME_POINTS_REWARD,  target.getPointsReward());
        
        return values;
    }

    /**
     * Updates the values of a target in the database.
     * @param target The target to be updated.
     * @return The number of rows updated.
     */
    public int UpdateTarget(Target target) {
        if(target.getId() == -1){
            throw new AssertionError("ID of -1 indicated target is not in database, therfore updating is a fault.");
        }
        
        ContentValues values = createContentValues(target);
        return database.update(
                TargetContract.TABLE_NAME, 
                values, 
                TargetContract._ID + " = '" + target.getId() + "'", 
                null);
    }

    /**
     * Deletes the given target from the database.
     * @param target The target to be removed.
     * @return The number of rows removed.
     */
    public int deleteTarget(Target target) {
        if(target.getId() == -1){
            throw new AssertionError("ID of -1 indicated target is not in database, therfore deleting is a fault.");
        }
        
        return database.delete(
                TargetContract.TABLE_NAME, 
                TargetContract._ID + " = '" + target.getId() + "'", 
                null);
    }

}
